package org.peterbjornx.net;

import org.peterbjornx.io.RSInputStream;
import org.peterbjornx.io.RSOutputStream;
import org.peterbjornx.Client;
import org.peterbjornx.net.packet.*;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;

/**
 * Created by IntelliJ IDEA.
 * User: PeterbjornX
 * Date: Apr 9, 2009
 * Time: 2:46:29 PM
 * Handles incoming packets
 */
public class PacketHandler extends Thread{
    private RSInputStream instream;
    private RSOutputStream outstream;
    private Client clientinstance;
    private ByteArrayOutputStream byteout;
    private RSOutputStream realoutstream;
    private boolean outstream_busy = false;
    private boolean shutdown = false;
    private HashMap<Integer, Packet> packetmap = new HashMap<Integer,Packet>();

    public PacketHandler(Client c,InputStream _instream, OutputStream _outstream,int[] isaac) {
        super("Packetprocessor");
        instream = new RSInputStream(_instream,0);
        realoutstream = new RSOutputStream(_outstream);
        byteout = new ByteArrayOutputStream();
        for (int i = 0;i < isaac.length;i++)
            isaac[i]+=50;
        instream.initISAACCypher(isaac);
        clientinstance = c;
        packetmap.put(253,new ServerMessage());
        packetmap.put(73,new RegionSelect());
        packetmap.put(81,new PlayerUpdate());
        packetmap.put(249,new ClientInit());
    }

    public boolean isOutstreamBusy(){
        return outstream_busy;
    }

    private void flush() throws IOException {
        outstream.flush();
        byte d[] = byteout.toByteArray();
        realoutstream.write(d);
        byteout = new ByteArrayOutputStream();
        outstream.set(byteout);
    }

    public void stop_processor(){
        shutdown = true;
    }

    public void run(){
        while(!shutdown){
            try {
                process();
            } catch (IOException e) {
                /*EMPTY*/
            }
        }
    }
    private void wait_in(int bytes) throws IOException {
        while (instream.available() < bytes)
            try {
                synchronized(instream)
                {
                    instream.wait(10);
                }
            } catch (InterruptedException e) {
                /*EMPTY*/
            }
    }
    private void process() throws IOException {
        wait_in(1); // Wait for the opcode to arrive
        int opcode = instream.readISAACByte();
        int size = packetSizes[opcode];
        if (size == -1)
        {
            wait_in(1);//Wait for the sizebyte to arrive
            size = instream.read()&0xff;
        } else if (size == -2){
            wait_in(2);//Wait for the sizeshort to arrive
            size = instream.readUShort();
        }
        wait_in(size);//Wait for the payload
        Packet p = packetmap.get(opcode);
        if (p != null)
            p.handleData(instream, clientinstance, size);
        else
        {
            //System.err.println("[PacketHandler] Unhandled packet : "+opcode+" of size "+size);
            instream.skip(size);
        }
    }
    
    public static final int[] packetSizes = {
        0, 0, 0, 0, 6, 0, 0, 0, 4, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
        0, 0, 0, 0, -2, 4, 3, 0, 0, 0,
        0, 0, 0, 0, 5, 0, 0, 6, 0, 0,
        9, 0, 0, -2, 0, 0, 0, 0, 0, 0,
        -2, 1, 0, 0, 2, -2, 0, 0, 0, 0,
        6, 3, 2, 4, 2, 4, 0, 0, 0, 4,
        0, -2, 0, 0, 7, 2, 0, 6, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 2, 0, 1,
        0, 2, 0, 0, -1, 4, 1, 0, 0, 0,
        1, 0, 0, 0, 2, 0, 0, 15, 0, 0,
        0, 4, 4, 0, 0, 0, -2, 0, 0, 0,
        0, 0, 0, 0, 6, 0, 0, 0, 0, 0,
        0, 0, 2, 0, 0, 0, 0, 14, 0, 0,
        0, 4, 0, 0, 0, 0, 3, 0, 0, 0,
        4, 0, 0, 0, 2, 0, 6, 0, 0, 0,
        0, 3, 0, 0, 5, 0, 10, 6, 0, 0,
        0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, -1, 0, 0, 0,
        4, 0, 0, 0, 0, 0, 3, 0, 2, 0,
        0, 0, 0, 0, -2, 7, 0, 0, 2, 0,
        0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
        8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        2, -2, 0, 0, 0, 0, 6, 0, 4, 3,
        0, 0, 0, -1, 6, 0, 0
    };
}
